#include "GameApp.h"


CGameApp::CGameApp()
{
	m_hWnd				= NULL;
	m_usLastFrameRate	= 0;
	m_usFrameRate		= 0;
	m_bActiveRender		= TRUE;
	m_bLostDevice		= FALSE;
	m_bActiveKey		= TRUE;

	m_pD3D				= NULL;
	m_pD3DDevice		= NULL;


	D3DXMatrixIdentity(&m_mtxView);
	D3DXMatrixIdentity(&m_mtxProjection);

}

CGameApp::~CGameApp()
{
	//Do nothing
}

BOOL CGameApp::GameInit(HINSTANCE hInstance)
{

	///-------------------------------------------------------------------------------------------
	// Init window ------------------------------------------------------------------------------
	///-------------------------------------------------------------------------------------------
	if (!InitWindow(hInstance))
	{
		return FALSE;
	}

	///-------------------------------------------------------------------------------------------
	// Init direct3D ------------------------------------------------------------------------------
	///-------------------------------------------------------------------------------------------
	if (!InitDirect3D())
	{
		return FALSE;
	}

	return TRUE;
}



BOOL CGameApp::InitWindow(HINSTANCE hInstance)
{
	WNDCLASS	wndc;

	wndc.cbClsExtra		= 0;
	wndc.cbWndExtra		= 0;
	wndc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndc.hInstance		= hInstance;
	wndc.hCursor		= LoadCursor(hInstance, IDC_ARROW);;
	wndc.hIcon			= NULL;
	wndc.lpfnWndProc	= StaticWinProc;
	wndc.lpszClassName	= "Excercise 2";
	wndc.lpszMenuName	= NULL;
	wndc.style			= CS_HREDRAW | CS_VREDRAW;

	if (!RegisterClass(&wndc))
	{
		MessageBox(0, "Can not Register Class", "Error", MB_OK);
		return FALSE;
	}

	m_hWnd	= CreateWindow("Excercise 2",
						   "Excercise 2",
						   WS_OVERLAPPEDWINDOW,
						   100,
						   100,
						   SCREEN_WIDTH,
						   SCREEN_HEIGHT,
						   NULL,
						   NULL,
						   hInstance,
						   this);
	if ( !m_hWnd)
	{
		MessageBox(0, "Can not Create Window", "Error", MB_OK);
		return FALSE;
	}

	ShowWindow(m_hWnd, SW_SHOW);
	UpdateWindow(m_hWnd);

	return TRUE;
}

BOOL CGameApp::InitDirect3D()
{
	D3DPRESENT_PARAMETERS	D3DPresentParam;
	D3DCAPS9				Caps;

	ZeroMemory(&D3DPresentParam, sizeof(D3DPresentParam));
	ZeroMemory(&Caps, sizeof(Caps));
	D3DPresentParam.BackBufferCount				= 1;
	D3DPresentParam.BackBufferFormat			= D3DFMT_UNKNOWN;
	D3DPresentParam.hDeviceWindow				= m_hWnd;
	D3DPresentParam.SwapEffect					= D3DSWAPEFFECT_DISCARD;
	D3DPresentParam.Windowed					= TRUE;
	D3DPresentParam.PresentationInterval		= D3DPRESENT_INTERVAL_IMMEDIATE;
	D3DPresentParam.AutoDepthStencilFormat		= D3DFMT_D16;
	D3DPresentParam.EnableAutoDepthStencil		= TRUE;


	ULONG ulFlag = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

	m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);

	if (!m_pD3D)
	{
		MessageBox(0, "Can not create Direct3D", "Error", MB_OK);
		return FALSE;
	}

	m_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &Caps);
	if (Caps.DeviceType & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
	{
		ulFlag	= D3DCREATE_HARDWARE_VERTEXPROCESSING;
	}

	if (FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, ulFlag, &D3DPresentParam, &m_pD3DDevice)))
	{

		m_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, &Caps);
		if (Caps.DeviceType & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
		{
			ulFlag	= D3DCREATE_HARDWARE_VERTEXPROCESSING;
		}

		if (FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, m_hWnd, ulFlag, &D3DPresentParam, &m_pD3DDevice)))
		{
			MessageBox(0, "Can not create Device", "Error", MB_OK);
			return FALSE;
		}
	}

	m_D3DPresentParam = D3DPresentParam;

	return TRUE;
}

LPDIRECT3DDEVICE9 CGameApp::GetDevice()
{
	return m_pD3DDevice;
}



void CGameApp::GameRun()
{
	MSG	msg;
	ZeroMemory(&msg, sizeof(msg));

	while (1)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
			{
				break;
			}
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			FrameAdvance();
		}
	}
}

void CGameApp::FrameAdvance()
{
	m_Timer.Tick();

	if(!m_bActiveRender)
		return;
	
	// Get and show FPS
	m_usFrameRate = m_Timer.GetFrameRate();
	if(m_usFrameRate != m_usLastFrameRate)
	{
		static TCHAR FPS[20];
		m_Timer.GetFrameRate(FPS);
		m_usLastFrameRate = m_usFrameRate;
		SetWindowText(m_hWnd, FPS);
	}

	// Recover when lost device
	if(m_bLostDevice)
	{
		HRESULT hr = m_pD3DDevice->TestCooperativeLevel();
		if(hr == D3DERR_DEVICENOTRESET)
		{
			m_pD3DDevice->Reset(&m_D3DPresentParam);
			m_bLostDevice = FALSE;
		}
		else
		{
			return;
		}
	}

	// Render function
	UpdateGame();
	Render();
}




void CGameApp::UpdateGame()
{
	
}

void CGameApp::Render()
{
	
}

void CGameApp::GameEnd()
{
	if (m_pD3D)
	{
		m_pD3D->Release();
		m_pD3D = NULL;
	}

	if (m_pD3DDevice)
	{
		m_pD3DDevice->Release();
		m_pD3DDevice = NULL;
	}

	if (m_hWnd)
	{
		DestroyWindow(m_hWnd);
		m_hWnd = NULL;
	}
}

LRESULT CALLBACK CGameApp::StaticWinProc(HWND hWindow, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
	if  ( iMessage == WM_CREATE ) 
		SetWindowLong( hWindow, GWL_USERDATA, (LONG)((CREATESTRUCT FAR *)lParam)->lpCreateParams);

	CGameApp *MyGame = (CGameApp*)GetWindowLong( hWindow, GWL_USERDATA );

	if  (MyGame) 
		return MyGame->WinProc( hWindow, iMessage, wParam, lParam );

	return DefWindowProc(hWindow, iMessage, wParam, lParam);
}

LRESULT CGameApp::WinProc(HWND hWindow, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
	switch (iMessage)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_SIZE:
		if  (wParam == SIZE_MINIMIZED)
		{
			// Stop render when minimize
			m_bActiveRender = FALSE;
		}
		else
		{
			m_bActiveRender = TRUE;
		}
		break;
	}

	return DefWindowProc(hWindow, iMessage, wParam, lParam);
}

